home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / C / Applications / Python 1.3.3 / Python 133 68K / Demo / www / mainloop.py < prev    next >
Text File  |  1996-05-20  |  6KB  |  235 lines

  1. # Standard main loop for *all* STDWIN applications.
  2. # This requires that applications:
  3. # - register their windows on creation and unregister them when closed
  4. # - have a 'dispatch' function as a window member
  5.  
  6.  
  7. import stdwin, stdwinq
  8. from stdwinevents import *
  9.  
  10.  
  11. # List of windows known to the main loop.
  12. #
  13. windows = []
  14.  
  15.  
  16. # Last window that ever received an event
  17. #
  18. last_window = None
  19.  
  20.  
  21. # Function to register a window.
  22. #
  23. def register(win):
  24.     # First test the dispatch function by passing it a null event --
  25.     # this catches registration of unconforming windows.
  26.     win.dispatch((WE_NULL, win, None))
  27.     if win not in windows:
  28.         windows.append(win)
  29.  
  30.  
  31. # Function to unregister a window.
  32. # It is not an error to unregister an already unregistered window
  33. # (this is useful for cleanup actions).
  34. #
  35. def unregister(win):
  36.     global last_window
  37.     if win == last_window:
  38.         last_window = None
  39.     if win in windows:
  40.         windows.remove(win) # Not in 0.9.1
  41.         # 0.9.1 solution:
  42.         #for i in range(len(windows)):
  43.         #    if windows[i] = win:
  44.         #        del windows[i]
  45.         #        break
  46.  
  47.  
  48. # Interfaces used by WindowSched.
  49. #
  50. def countwindows():
  51.     return len(windows)
  52. #
  53. def anywindow():
  54.     if windows:
  55.         return windows[0]
  56.     else:
  57.         return None
  58.  
  59.  
  60. # NEW: register any number of file descriptors
  61. #
  62. fdlist = []
  63. select_args = None
  64. select_handlers = None
  65. #
  66. def registerfd(fd, mode, handler):
  67.     if mode not in ('r', 'w', 'x'):
  68.         raise ValueError, 'mode must be r, w or x'
  69.     if type(fd) <> type(0):
  70.         fd = fd.fileno() # If this fails it's not a proper select arg
  71.     for i in range(len(fdlist)):
  72.         if fdlist[i][:2] == (fd, mode):
  73.             raise ValueError, \
  74.                 '(fd, mode) combination already registered'
  75.     fdlist.append((fd, mode, handler))
  76.     make_select_args()
  77. #
  78. def unregisterfd(fd, *args):
  79.     if type(fd) <> type(0):
  80.         fd = fd.fileno() # If this fails it's not a proper select arg
  81.     args = (fd,) + args
  82.     n = len(args)
  83.     for i in range(len(fdlist)):
  84.         if fdlist[i][:n] == args:
  85.             del fdlist[i]
  86.     make_select_args()
  87. #
  88. def make_select_args():
  89.     global select_args, select_handlers
  90.     rlist, wlist, xlist = [], [], []
  91.     rhandlers, whandlers, xhandlers = {}, {}, {}
  92.     for fd, mode, handler in fdlist:
  93.         if mode == 'r':
  94.             rlist.append(fd)
  95.             rhandlers[`fd`] = handler
  96.         if mode == 'w':
  97.             wlist.append(fd)
  98.             whandlers[`fd`] = handler
  99.         if mode == 'x':
  100.             xlist.append(fd)
  101.             xhandlers[`fd`] = handler
  102.     if rlist or wlist or xlist:
  103.         select_args = rlist, wlist, xlist
  104.         select_handlers = rhandlers, whandlers, xhandlers
  105.     else:
  106.         select_args = None
  107.         select_handlers = None
  108. #
  109. def do_select():
  110.     import select
  111.     reply = apply(select.select, select_args)
  112.     for mode in 0, 1, 2:
  113.         list = reply[mode]
  114.         for fd in list:
  115.             handler = select_handlers[mode][`fd`]
  116.             handler(fd, 'rwx'[mode])
  117.  
  118.  
  119. # Event processing main loop.
  120. # Return when there are no windows left, or when an unhandled
  121. # exception occurs.  (It is safe to restart the main loop after
  122. # an unsuccessful exit.)
  123. # Python's stdwin.getevent() turns WE_COMMAND/WC_CANCEL events
  124. # into KeyboardInterrupt exceptions; these are turned back in events.
  125. #
  126. def mainloop():
  127.     stdwin_select_handler() # Process events already in stdwin queue
  128.     fd = stdwin.fileno()
  129.     while 1:
  130.         if windows:
  131.             registerfd(fd, 'r', stdwin_select_handler)
  132.             try:
  133.                 while windows:
  134.                     do_select()
  135.                     stdwin_select_handler()
  136.             finally:
  137.                 unregisterfd(fd)
  138.         elif fdlist:
  139.             while fdlist and not windows:
  140.                 do_select()
  141.         else:
  142.             break
  143.  
  144.  
  145. # Handle stdwin events until none are left
  146. #
  147. def stdwin_select_handler(*args):
  148.     while 1:
  149.         try:
  150.             event = stdwinq.pollevent()
  151.         except KeyboardInterrupt:
  152.             event = (WE_COMMAND, None, WC_CANCEL)
  153.         if event is None:
  154.             break
  155.         dispatch(event)
  156.  
  157.  
  158. # Run a modal dialog loop for a window.  The dialog window must have
  159. # been registered first.  This prohibits most events (except size/draw
  160. # events) to other windows.  The modal dialog loop ends when the
  161. # dialog window unregisters itself.
  162. #
  163. passthrough = WE_SIZE, WE_DRAW
  164. beeping = WE_MOUSE_DOWN, WE_COMMAND, WE_CHAR, WE_KEY, WE_CLOSE, WE_MENU
  165. #
  166. def modaldialog(window):
  167.     if window not in windows:
  168.         raise ValueError, 'modaldialog window not registered'
  169.     while window in windows:
  170.         try:
  171.             event = stdwinq.getevent()
  172.         except KeyboardInterrupt:
  173.             event = WE_COMMAND, None, WC_CANCEL
  174.         etype, ewindow, edetail = event
  175.         if etype not in passthrough and ewindow <> window:
  176.             if etype in beeping:
  177.                 stdwin.fleep()
  178.             continue
  179.         dispatch(event)
  180.  
  181.  
  182. # Dispatch a single event.
  183. # Events for the no window in particular are sent to the active window
  184. # or to the last window that received an event (these hacks are for the
  185. # WE_LOST_SEL event, which is directed to no particular window).
  186. # Windows not in the windows list don't get their events:
  187. # events for such windows are silently ignored.
  188. #
  189. def dispatch(event):
  190.     global last_window
  191.     if event[1] == None:
  192.         active = stdwin.getactive()
  193.         if active: last_window = active
  194.     else:
  195.         last_window = event[1]
  196.     if last_window in windows:
  197.         last_window.dispatch(event)
  198.  
  199.  
  200. # Dialog base class
  201. #
  202. class Dialog:
  203.     #
  204.     def init(self, title):
  205.         self.window = stdwin.open(title)
  206.         self.window.dispatch = self.dispatch
  207.         register(self.window)
  208.         return self
  209.     #
  210.     def close(self):
  211.         unregister(self.window)
  212.         del self.window.dispatch
  213.         self.window.close()
  214.     #
  215.     def dispatch(self, event):
  216.         etype, ewindow, edetail = event
  217.         if etype == WE_CLOSE:
  218.             self.close()
  219.  
  220.  
  221. # Standard modal dialogs
  222. # XXX implemented using stdwin dialogs for now
  223. #
  224. def askstr(prompt, default):
  225.     return stdwin.askstr(prompt, default)
  226. #
  227. def askync(prompt, yesorno):
  228.     return stdwin.askync(prompt, yesorno)
  229. #
  230. def askfile(prompt, default, new):
  231.     return stdwin.askfile(prompt, default, new)
  232. #
  233. def message(msg):
  234.     stdwin.message(msg)
  235.